package modelPackage;

import java.awt.Point;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import modelPackage.Sprite;
import modelPackage.Map;



/**
 * The world manager needs to know all of the model, as well as knowing what specifically is on the screen.
 */
public class WorldManager implements WorldManagerInterface {
	
	//The world manager manages all the maps for all the players and whatnots.	
	private ArrayList<Map3D> maps;
	private ArrayList<Map> littleMaps;
	private ArrayList<Player> players;
	
	//Some constants.
	static private int TILE_SIZE = 50;
	static private double GRAVITY = 0.0085;
	
	/**
	 * Creates the entire world.
	 */
	public WorldManager() {
		maps = new ArrayList<Map3D>();
		players = new ArrayList<Player>();
		littleMaps = new ArrayList<Map>();
		
		/*
		 * Start by loading all the maps.
		 * */
		BufferedReader file = null;
		try {
			file = new BufferedReader(new FileReader("map/maps.txt"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		String line = null;
		//Read in each line from the text file.
		while (true) {
			try {
				line = file.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			//If a null line is read in, stop reading lines.
			if (line == null) {
				try {
					file.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				break;
			}
			
			//If the line is commented out, ignore it.
			//Comments can be signified by // -- # * ;
			if (line.startsWith("//") || line.startsWith("--") || line.startsWith("#") || line.startsWith("*") || line.startsWith(";")) {
				//Do nothing.
			}
			
			else {
				
				Map3D newMap = new Map3D(line);
				
				maps.add(newMap);
				
				for (int i = 0; i < newMap.getMaps().size(); i++) {
					this.littleMaps.add(newMap.getMaps().get(i));
				}
			}
		}
		
		/*
		 * After loading all the maps, then we do...some stuff????
		 * */
		
	}
	
	/**
	 * Update the position of each sprite based on the velocity and time passed.  
	 * Since updates occur on a fixed time interval, this is quite simple.
	 */
	public void updateSprites(long elapsedTime) {
		
		//Start with the players list.
		if (this.players.size() != 0) {
			for (int i = 0; i < this.players.size(); i++) {
				
				//Kills the player and starts from the start if the screen if the player falls down a hole
				if(this.players.get(i).getPosition().y > this.players.get(i).getMap().getHeight()*TILE_SIZE){
					this.players.get(i).collide();
				}
				
				
				//Gravity always applies to every player.
				if (this.players.get(i).getYVelocity() < 1) {
					this.players.get(i).setYVelocity(this.players.get(i).getYVelocity() + GRAVITY*elapsedTime);
				}
				
				
				
				
				
				
				//For each player, update X position and check for collisions with tiles.
				int tempX = this.players.get(i).updateXPosition(elapsedTime);
				
				//If the new position is outside the bounds of the world, adjust it accordingly.
				if (tempX < 0) {
					tempX = 0;
				}
				else if (tempX + this.players.get(i).getWidth() > this.players.get(i).getMap().getWidth()*TILE_SIZE) {
					tempX = this.players.get(i).getMap().getWidth()*TILE_SIZE - this.players.get(i).getWidth();
				}
				
				//Then, if you've moved at all, check for collisions.
				if (tempX != this.players.get(i).getPosition().x) {
					int newX = 0;
					if (this.players.get(i).getMode() == 2) {					
						newX = this.doTileXCollision(this.players.get(i), this.players.get(i), tempX);
					}
					else if (this.players.get(i).getMode() == 3) {
						newX = this.do3DTileXCollision(this.players.get(i), this.players.get(i), tempX);
					}
					this.players.get(i).setXPosition(newX);
					
					//This may need some work?
					this.spriteCollisionX(this.players.get(i), this.players.get(i));
				}
				
				
				
				
				
				
				//For each player, update Z position and check for collisions with tiles.
				int tempZ = this.players.get(i).updateZPosition(elapsedTime);
				
				//If the new position is outside the bounds of the world, adjust it accordingly.
				if (tempZ < 0) {
					tempZ = 0;
				}
				else if (tempZ + this.players.get(i).getDepth() > this.players.get(i).get3DMap().getDepth()*TILE_SIZE) {
					tempZ = this.players.get(i).get3DMap().getDepth()*TILE_SIZE - this.players.get(i).getDepth();
				}
				
				//Then, if you've moved at all, check for collisions.
				//Z collisions only ever happen in 3D mode.
				if (tempZ != this.players.get(i).get3DPosition().z) {
					int newZ = this.do3DTileZCollision(this.players.get(i), this.players.get(i), tempZ);
					this.players.get(i).setZPosition(newZ);
					
					//This might need some work?
					this.spriteCollisionZ(this.players.get(i), this.players.get(i));
				}
				
				
				
				
				
				//For each player, update Y position and check for collisions with tiles.
				int tempY = this.players.get(i).updateYPosition(elapsedTime);
				
				//Don't stop the player from going outside the bounds of the world in the y.
				//You can jump off the world in the top and just fall back down.
				//And falling out of the world kills you.
				
				//If you've moved at all, check for collisions
				if (tempY != this.players.get(i).getPosition().y) {
					int newY = 0;
					if (this.players.get(i).getMode() == 2) {
						newY = this.doTileYCollision(this.players.get(i), this.players.get(i), tempY);
					}
					else if (this.players.get(i).getMode() == 3) {
						newY = this.do3DTileYCollision(this.players.get(i), this.players.get(i), tempY);
					}
					this.players.get(i).setYPosition(newY);
					
					//This might need some work?
					this.spriteCollisionY(this.players.get(i), this.players.get(i));
				}
				
				
				
				
				//Then update the animation.
				this.players.get(i).updateAnimation(elapsedTime);
				
				// Now that all of the positions are updated, check for death and map changes.
				if (this.players.get(i).getRemainingLives() == 0) {
					this.newGame(this.players.get(i).getID());
				}
				this.doMapChange(this.players.get(i));
				
										
				
						
				//Then update all the other sprites.
				
				//Need to do this for 3d too.  should be simple once the functions are in place.
				
				if (this.players.get(i).getMap().getSprites().size() != 0) {
					//For each sprite on the map, update position and check for collisions with tiles.
					for (int j = 0; j < this.players.get(i).getMap().getSprites().size(); j++) {
						
						if (this.players.get(i).getMap().getSprites().get(j).getDead() == false) {
						
							//if the sprite is off the screen, set it to dead.
							if(this.players.get(i).getMap().getSprites().get(j).getPosition().y > this.players.get(i).getMap().getHeight()*TILE_SIZE){
								this.players.get(i).getMap().getSprites().get(j).setDead(true);
							}
							
							//If sprite isn't flying, or isn't active, apply gravity.
							if (this.players.get(i).getMap().getSprites().get(j).getFlying() == false || this.players.get(i).getMap().getSprites().get(j).getActive() == false) {
								if (this.players.get(i).getMap().getSprites().get(j).getYVelocity() < 1) {
									this.players.get(i).getMap().getSprites().get(j).setYVelocity(this.players.get(i).getMap().getSprites().get(j).getYVelocity() + GRAVITY*elapsedTime);
								}
							}
						
							//First update and check in the X.
							int tempX2 = this.players.get(i).getMap().getSprites().get(j).updateXPosition(elapsedTime, this.players.get(i).getMap().getSprites().get(j).getXVelocity());
							if(this.players.get(i).getMap().getSprites().get(j).getActive() == true) {
								int newX2 = this.doTileXCollision(this.players.get(i).getMap().getSprites().get(j), this.players.get(i), tempX2);
								this.players.get(i).getMap().getSprites().get(j).setXPosition(newX2);
								this.spriteCollisionX(this.players.get(i).getMap().getSprites().get(j), this.players.get(i));
							}
							else {
								this.players.get(i).getMap().getSprites().get(j).setXPosition(tempX2);
							}
						
							//Then update and check in the Z.
							int tempZ2 = this.players.get(i).getMap().getSprites().get(j).updateZPosition(elapsedTime, this.players.get(i).getMap().getSprites().get(j).getZVelocity());
							if(this.players.get(i).getMap().getSprites().get(j).getActive() == true) {
								int newZ2 = this.do3DTileZCollision(this.players.get(i).getMap().getSprites().get(j), this.players.get(i), tempZ2);
								this.players.get(i).getMap().getSprites().get(j).setZPosition(newZ2);
								//this.spriteCollisionZ(this.players.get(i).getMap().getSprites().get(j), this.players.get(i));
							}
							else {
								this.players.get(i).getMap().getSprites().get(j).setZPosition(tempZ2);
							}
						
							//Then update and check in the Y.
							int tempY2 = this.players.get(i).getMap().getSprites().get(j).updateYPosition(elapsedTime);
							if(this.players.get(i).getMap().getSprites().get(j).getActive() == true) {
								int newY2 = this.doTileYCollision(this.players.get(i).getMap().getSprites().get(j), this.players.get(i), tempY2);
								this.players.get(i).getMap().getSprites().get(j).setYPosition(newY2);
								this.spriteCollisionY(this.players.get(i).getMap().getSprites().get(j), this.players.get(i));
							}
							else {
								this.players.get(i).getMap().getSprites().get(j).setYPosition(tempY2);
							}
						
							//Then update the animation.
							this.players.get(i).getMap().getSprites().get(j).updateAnimation(elapsedTime);
						}	
					}
				}
			}
		}
	}
	
	
	
	

	
	public void spriteCollisionX(Sprite s, Player p) {
		int pMinX = s.getPosition().x;
		int pMaxX = s.getPosition().x + s.getWidth();
		int pMinY = s.getPosition().y;
		int pMaxY = s.getPosition().y + s.getHeight();
		
		Point topLeft = new Point(pMinX+1, pMinY+1);						
		Point topRight = new Point(pMaxX-1, pMinY+1);
		Point bottomLeft = new Point(pMinX+1, pMaxY-1);
		Point bottomRight = new Point(pMaxX-1, pMaxY-1);
		
		Sprite STL = getSprite(topLeft, p);
		Sprite STR = getSprite(topRight, p);
		Sprite SBL = getSprite(bottomLeft, p);
		Sprite SBR = getSprite(bottomRight, p);
		
		if (s instanceof Player) {
			if (STL != null || STR != null || SBL != null || SBR != null) {
				s.collide();
			}
		}
		else {
			//If a sprite runs into another sprite, change it's direction (set velocity = 0).
			if ((STL != null && STL != s) || (SBL != null && SBL != s)) {
				s.setNegXVelocity(false);
				if (STL != null) {
					if (STL.getNegXVelocity() == true) {
						//Do nothing.
					}
					else if (STL.getNegXVelocity() == false) {
						STL.setNegXVelocity(true);
					}
				}
				if (SBL != null) {
					if (SBL.getNegXVelocity() == true) {
						//Do nothing.
					}
					else if (SBL.getNegXVelocity() == false) {
						SBL.setNegXVelocity(true);
					}
				}
			}
			else if ((STR != null && STR != s) || (SBR != null && SBR != s)) {
				s.setPosXVelocity(false);
				if (STR != null) {
					if (STR.getPosXVelocity() == true) {
						//Do nothing.
					}
					else if (STR.getPosXVelocity() == false) {
						STR.setPosXVelocity(true);
					}
				}
				if (SBR != null) {
					if (SBR.getPosXVelocity() == true) {
						//Do nothing.
					}
					else if (SBR.getPosXVelocity() == false) {
						SBR.setPosXVelocity(true);
					}
				}
			}
		}
		
	}
	
	//This section needs work.  I need to know how to kill a bear.  I don't really know right now.
	public void spriteCollisionY(Sprite s, Player p) {
		int pMinX = s.getPosition().x;
		int pMaxX = s.getPosition().x + s.getWidth();
		int pMinY = s.getPosition().y;
		int pMaxY = s.getPosition().y + s.getHeight();
		
		Point topLeft = new Point(pMinX+1, pMinY+1);						
		Point topRight = new Point(pMaxX-1, pMinY+1);
		Point bottomLeft = new Point(pMinX+1, pMaxY-1);
		Point bottomRight = new Point(pMaxX-1, pMaxY-1);
		
		Sprite STL = getSprite(topLeft, p);
		Sprite STR = getSprite(topRight, p);
		Sprite SBL = getSprite(bottomLeft, p);
		Sprite SBR = getSprite(bottomRight, p);
		
		if (s instanceof Player) {
			if (STL != null || STR != null) { 
				s.collide();
			}
			else if (SBL != null || SBR != null) {
				if (SBL != null) {
					SBL.collide();
					//Do something here...
				}
				else if (SBR != null) {
					SBR.collide();
					//Do something here...
				}
			}
		}
		else {
			//If a sprite runs into another sprite, change it's direction (set velocity = 0).
			if (STL != null || SBL != null || STR != null || SBR != null) {
				s.setYVelocity(0);
			}
		}
		
	}
	public void spriteCollisionZ(Sprite s, Player p) {
		//Do something here...
	}
	
	
	public Sprite getSprite(Point p, Player player) {
		if (player.getMap().getSprites().size() != 0) {
			for (int i = 0; i < player.getMap().getSprites().size(); i++) {
				if (((p.x >= player.getMap().getSprites().get(i).getPosition().x) && (p.x <= player.getMap().getSprites().get(i).getPosition().x + player.getMap().getSprites().get(i).getWidth())) 
						&& ((p.y >= player.getMap().getSprites().get(i).getPosition().y) && (p.y <= player.getMap().getSprites().get(i).getPosition().y + player.getMap().getSprites().get(i).getHeight())))
				{
					if (player.getMap().getSprites().get(i).getDead() == false && player.getMap().getSprites().get(i).getActive() == true) {
						return player.getMap().getSprites().get(i);
					}
				}
			}
		}
		return null;
	}
		
	public void newGame(String PlayerID) {
		this.getPlayer(PlayerID).setRemainingLives(5);
		this.getPlayer(PlayerID).setMap(this.maps.get(0));
		this.getPlayer(PlayerID).getPosition().x = 100;
		this.getPlayer(PlayerID).getPosition().y = 100;
	}
	
	
	public Tile getSolidTile(Point p, Player player) {
		
		if (this.players.size() != 0) {	
			for (int i = 0; i < this.players.size(); i++) {
				if (this.players.get(i) == player) {					
					return this.players.get(i).getMap().getSolidTile(p);
				}
			}
		}		
		return null;			
	}
	
	
	public Tile getTile(Point p, Player player) {
		
		if (this.players.size() != 0) {
			for (int i = 0; i < this.players.size(); i++) {
				if (this.players.get(i) == player) {
					return this.players.get(i).getMap().getTile(p);
				}
			}
		}
		
		return null;		
	}
	
	
	public void doMapChange(Player p) {
		
		Point playerMiddle = new Point((p.getPosition().x + (p.getWidth() / 2)), (p.getPosition().y + (p.getHeight() / 2)));
		
		Tile spriteTile = getTile(playerMiddle, p);
		
		if (spriteTile instanceof TeleportTile) {
			int newFloor = p.getMap().getTeleportFloors().get(((TeleportTile) spriteTile).getTeleportIndex());
			String newBuilding = p.getMap().getTeleportBuildings().get(((TeleportTile) spriteTile).getTeleportIndex());
			
			p.setMap(get3DMap(newBuilding, newFloor));
			p.setXPosition(100);
			p.setYPosition(100);
			return;
		}
	}
	
	/*
	 * For the next three functions, which perform collisions with tiles in 2D mode the input parameters are as follows:
	 * 
	 * Sprite s: The sprite which is colliding with the tiles.  This is the player if player is colliding with the tiles.
	 * Player p: The player which knows the map which contains the tiles which are being collided with.
	 * int oldX: The updated player position which may or may not be in collision with something.
	 * 
	 * Returns: The new corrected position, which if no collision is detected, will be the same as the old position.
	 * 
	 * */
	public int doTileXCollision(Sprite s, Player p, int newX) {
		int pMinX = newX;
		int pMaxX = newX + s.getWidth();
		int pMinY = s.getPosition().y;
		int pMaxY = s.getPosition().y + s.getHeight();
		
		Point topLeft = new Point(pMinX+1, pMinY+1);						
		Point topRight = new Point(pMaxX-1, pMinY+1);
		Point bottomLeft = new Point(pMinX+1, pMaxY-1);
		Point bottomRight = new Point(pMaxX-1, pMaxY-1);
		
		Tile TTL = getSolidTile(topLeft, p);
		Tile TTR = getSolidTile(topRight, p);
		Tile TBL = getSolidTile(bottomLeft, p);
		Tile TBR = getSolidTile(bottomRight, p);
		
		if (newX > s.getPosition().x) {
			if (TTR != null) { 
				s.setPosXVelocity(false);
				return TTR.getPosition().x - s.getWidth();
			}
			else if (TBR != null) {
				s.setPosXVelocity(false);
				return TBR.getPosition().x - s.getWidth();
			}
		}
		else if (newX < s.getPosition().x) {
			if (TTL != null) { 
				s.setNegXVelocity(false);
				return TTL.getPosition().x + TILE_SIZE;
			}
			else if (TBL != null) {
				s.setNegXVelocity(false);
				return TBL.getPosition().x + TILE_SIZE;
			}
		}
		return newX;
	}
	
	public int doTileYCollision(Sprite s, Player p, int newY) {
		int pMinX = s.getPosition().x;
		int pMaxX = s.getPosition().x + s.getWidth();
		int pMinY = newY;
		int pMaxY = newY + s.getHeight();
		
		Point topLeft = new Point(pMinX+1, pMinY+1);						
		Point topRight = new Point(pMaxX-1, pMinY+1);
		Point bottomLeft = new Point(pMinX+1, pMaxY-1);
		Point bottomRight = new Point(pMaxX-1, pMaxY-1);
		
		Tile TTL = getSolidTile(topLeft, p);
		Tile TTR = getSolidTile(topRight, p);
		Tile TBL = getSolidTile(bottomLeft, p);
		Tile TBR = getSolidTile(bottomRight, p);
		
		if (newY > s.getPosition().y) {
			if (TBL != null) { 
				s.setYVelocity(0);
				return TBL.getPosition().y - s.getHeight();
			}
			else if (TBR != null) {
				s.setYVelocity(0);
				return TBR.getPosition().y - s.getHeight();
			}
		}
		else if (newY < s.getPosition().y) {
			if (TTL != null) { 
				s.setYVelocity(0);
				return TTL.getPosition().y + TILE_SIZE;
			}
			else if (TTR != null) {
				s.setYVelocity(0);
				return TTR.getPosition().y + TILE_SIZE;
			}
		}
		return newY;
	}
	
	
	
	
	/*
	 * For the next three functions, the abbreviations are as follows:
	 * 	            Closer to Zero      Further from Zero
	 * X-Direction: N = Near            F = Far
	 * Y-Direction: T = Top             B = Bottom
	 * Z-Direction: L = Left            R = Right
	 * 
	 * */
	
	public int do3DTileXCollision(Sprite s, Player p, int newX) {
		int minX = newX;
		int maxX = newX + s.getWidth();
		int minY = s.getPosition().y;
		int maxY = s.getPosition().y + s.getHeight();
		int minZ = (int) s.get3DPosition().z;
		int maxZ = (int) s.get3DPosition().z + s.getDepth();
		
		Point NT = new Point(minX+1, minY+1);
		Point NB = new Point(minX+1, maxY-1);
		Point FT = new Point(maxX-1, minY+1);
		Point FB = new Point(maxX-1, maxY-1);
		
		int i1 = (minZ+1) / TILE_SIZE;
		int i2 = (maxZ-1) / TILE_SIZE;
		
		Map m1 = p.get3DMap().getMaps().get(i1);
		Map m2 = p.get3DMap().getMaps().get(i2);
		
		Tile NTL = m1.getSolidTile(NT);
		Tile NBL = m1.getSolidTile(NB);
		Tile FTL = m1.getSolidTile(FT);
		Tile FBL = m1.getSolidTile(FB);
		Tile NTR = m2.getSolidTile(NT);
		Tile NBR = m2.getSolidTile(NB);
		Tile FTR = m2.getSolidTile(FT);
		Tile FBR = m2.getSolidTile(FB);
	
		if (newX > s.getPosition().x) {
			//If you moved in the positive direction, you're dealing with the far side.			
			if (NTL != null) {
				s.setPosXVelocity(false);
				return NTL.getPosition().x - s.getWidth();
			}
			else if (NTR != null) {
				s.setPosXVelocity(false);
				return NTR.getPosition().x - s.getWidth();
			}
			else if (NBL != null) {
				s.setPosXVelocity(false);
				return NBL.getPosition().x - s.getWidth();
			}
			else if (NBR != null) {
				s.setPosXVelocity(false);
				return NBR.getPosition().x - s.getWidth();
			}
		}
		
		else if (newX < s.getPosition().x) {
			//If you moved in the negative direction, you're dealing with the near side.
			if (FTL != null) {
				s.setNegXVelocity(false);
				return FTL.getPosition().x + TILE_SIZE;
			}
			else if (FTR != null) {
				s.setNegXVelocity(false);
				return FTR.getPosition().x + TILE_SIZE;
			}
			else if (FBL != null) {
				s.setNegXVelocity(false);
				return FBL.getPosition().x + TILE_SIZE;
			}
			else if (FBR != null) {
				s.setNegXVelocity(false);
				return FBR.getPosition().x + TILE_SIZE;
			}
		}
		return newX;
	}
	
	public int do3DTileYCollision(Sprite s, Player p, int newY) {
		int minX = s.getPosition().x;
		int maxX = s.getPosition().x + s.getWidth();
		int minY = newY;
		int maxY = newY + s.getHeight();
		int minZ = (int) s.get3DPosition().z;
		int maxZ = (int) s.get3DPosition().z + s.getDepth();
		
		Point NT = new Point(minX+1, minY+1);
		Point NB = new Point(minX+1, maxY-1);
		Point FT = new Point(maxX-1, minY+1);
		Point FB = new Point(maxX-1, maxY-1);
		
		int i1 = (minZ+1) / TILE_SIZE;
		int i2 = (maxZ-1) / TILE_SIZE;
		
		Map m1 = p.get3DMap().getMaps().get(i1);
		Map m2 = p.get3DMap().getMaps().get(i2);
		
		Tile NTL = m1.getSolidTile(NT);
		Tile NBL = m1.getSolidTile(NB);
		Tile FTL = m1.getSolidTile(FT);
		Tile FBL = m1.getSolidTile(FB);
		Tile NTR = m2.getSolidTile(NT);
		Tile NBR = m2.getSolidTile(NB);
		Tile FTR = m2.getSolidTile(FT);
		Tile FBR = m2.getSolidTile(FB);
		
		if (newY > s.getPosition().y) {
			//If you moved in the positive direction, you're dealing with the bottom side.
			if (NBL != null) {
				s.setYVelocity(0);
				return NBL.getPosition().y - s.getHeight();
			}
			else if (FBL != null) {
				s.setYVelocity(0);
				return FBL.getPosition().y - s.getHeight();
			}
			else if (NBR != null) {
				s.setYVelocity(0);
				return NBR.getPosition().y - s.getHeight();
			}
			else if (FBR != null) {
				s.setYVelocity(0);
				return FBR.getPosition().y - s.getHeight();
			}
		}
		
		
		else if (newY < s.getPosition().y) {
			//If you moved in the negative direction, you're dealing with the top side.
			if (NTL != null) {
				s.setYVelocity(0);
				return NTL.getPosition().y + TILE_SIZE;
			}
			else if (FTL != null) {
				s.setYVelocity(0);
				return FTL.getPosition().y + TILE_SIZE;
			}
			else if (NTR != null) {
				s.setYVelocity(0);
				return NTR.getPosition().y + TILE_SIZE;
			}
			else if (FTR != null) {
				s.setYVelocity(0);
				return FTR.getPosition().y + TILE_SIZE;
			}
		}
		return newY;
	}
	
	public int do3DTileZCollision(Sprite s, Player p, int newZ) {
		int minX = s.getPosition().x;
		int maxX = s.getPosition().x + s.getWidth();
		int minY = s.getPosition().y;
		int maxY = s.getPosition().y + s.getHeight();
		int minZ = newZ;
		int maxZ = newZ + s.getDepth();
		
		Point NT = new Point(minX+1, minY+1);
		Point NB = new Point(minX+1, maxY-1);
		Point FT = new Point(maxX-1, minY+1);
		Point FB = new Point(maxX-1, maxY-1);
		
		int i1 = (minZ+1) / TILE_SIZE;
		int i2 = (maxZ-1) / TILE_SIZE;
		
		Map m1 = p.get3DMap().getMaps().get(i1);
		Map m2 = p.get3DMap().getMaps().get(i2);
		
		Tile NTL = m1.getSolidTile(NT);
		Tile NBL = m1.getSolidTile(NB);
		Tile FTL = m1.getSolidTile(FT);
		Tile FBL = m1.getSolidTile(FB);
		Tile NTR = m2.getSolidTile(NT);
		Tile NBR = m2.getSolidTile(NB);
		Tile FTR = m2.getSolidTile(FT);
		Tile FBR = m2.getSolidTile(FB);
		
		if (newZ > s.get3DPosition().z) {
			//If you moved in the positive direction, you're dealing with the right hand side.
			if (NTR != null || NBR != null || FTR != null || FBR != null) {
				s.setPosZVelocity(false);
				return (i2 * TILE_SIZE) - s.getDepth();
			}
		}
		else if (newZ < s.get3DPosition().z) {
			//If you moved in the negative direction, you're dealing with the left hand side.
			if (NTL != null || NBL != null || FTL != null || FBL != null) {
				s.setNegZVelocity(false);
				return (i1*TILE_SIZE) + TILE_SIZE;
			}
		}
		
		return newZ;
	}
	
	
	
	
	
	
	
	public Map getMap(String building, int floor) {
		if (maps.size() != 0) {
			for (int i = 0; i < maps.size(); i++) {
				if ((maps.get(i).getBuilding().equals(building)) && (maps.get(i).getFloor() == floor)) {
					return maps.get(i).get2DMap();
				}
			}
		}
		return null;
	}
	
	public Map3D get3DMap(String building, int floor) {
		if (maps.size() != 0) {
			for (int i = 0; i < maps.size(); i++) {
				if ((maps.get(i).getBuilding().equals(building)) && (maps.get(i).getFloor() == floor)) {
					return maps.get(i);
				}
			}
		}
		return null;
	}
	
	public void addPlayer(Player p) {
		players.add(p);
	}
	
	
	public void removePlayer(Player p) {
		players.remove(p);
	}
	
	
	public ArrayList<Player> getPlayers() {
		return players;
	}
	
	
	public Player getPlayer(String PlayerID) {
		if (players.size() != 0) {
			for (int i = 0; i < players.size(); i++) {
				if (players.get(i).getID().equals(PlayerID)) {
					return players.get(i);
				}
			}
		}
		return null;
	}
	
}